/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.gorkemozbek.rubic.util.struct

import scala.collection.immutable.{Set, List}

sealed abstract class Struct

// Boolean Structure
class BooleanStruct private[struct] (override val self: Boolean) extends Struct with Proxy

object BooleanStruct {

  def apply(b: Boolean): BooleanStruct = new BooleanStruct(b)

  def unapply(s: Struct): Option[Boolean] = s match {
    case x: BooleanStruct => Some(x.self)
    case _ => None
  }

}

// Numeric Structure
class NumericStruct private[struct] (override val self: Double) extends Struct with Proxy

object NumericStruct {

  def apply(b: Byte): NumericStruct = new NumericStruct(b.toDouble)

  def apply(s: Short) = new NumericStruct(s.toDouble)

  def apply(i: Int) = new NumericStruct(i.toDouble)

  def apply(l: Long) = new NumericStruct(l.toDouble)

  def apply(f: Float) = new NumericStruct(f.toDouble)

  def apply(d: Double) = new NumericStruct(d)

  def unapply(s: Struct): Option[Double] = s match {
    case x: NumericStruct => Some(x.self)
    case _ => None
  }

}

// Textual Structure
class TextualStruct private[struct] (override val self: String) extends Struct with Proxy

object TextualStruct {

  def apply(c: Char): TextualStruct = new TextualStruct(c.toString)

  def apply(s: String): TextualStruct = new TextualStruct(s)

  def unapply(s: Struct): Option[String] = s match {
    case x: TextualStruct => Some(x.self)
    case _ => None
  }

}

// Set Structure
class SetStruct private[struct] (override val self: StructureSet) extends Struct with Proxy

object SetStruct {

  def apply(sset: Struct*): SetStruct = apply(sset.toSet)

  def apply(sset: StructureSet): SetStruct = new SetStruct(sset)

  def unapply(s: Struct): Option[StructureSet] = s match {
    case x: SetStruct => Some(x.self)
    case _ => None
  }

}

// List Structure
class ListStruct private[struct] (override val self: StructureList) extends Struct with Proxy

object ListStruct {

  def apply(slist: Struct*): ListStruct = apply(slist.toList)

  def apply(slist: StructureList): ListStruct = new ListStruct(slist)

  def unapply(s: Struct): Option[StructureList] = s match {
    case x: ListStruct => Some(x.self)
    case _ => None
  }

}
// Table Structure
class TableStruct private[struct] (override val self: FeatureList) extends Struct with Proxy

object TableStruct {

  implicit val FeatureOrdering = new Ordering[Feature] {
    def compare(f1: Feature, f2: Feature): Int = f1.name compareTo f2.name
  }

  def sortFeatureList(fs: FeatureList): FeatureList = fs sortBy { _._1 }

  def apply(fs: FeatureEntry*): TableStruct = apply(fs.toList)

  def apply(fs: FeatureList): TableStruct = new TableStruct(sortFeatureList(fs))

  def unapply(s: Struct): Option[FeatureList] = s match {
    case x: TableStruct => Some(x.self)
    case _ => None
  }

}